package com.jddup.program.dao;

import com.jddup.common.exception.JddupException;
import com.jddup.program.dao.handler.IDeleteHandler;
import com.jddup.program.dao.handler.IInsertHandler;
import com.jddup.program.dao.handler.IQueryHandler;
import com.jddup.program.dao.handler.IUpdateHandler;
import com.jddup.program.dao.handler.impl.DeleteHandlerImpl;
import com.jddup.program.dao.handler.impl.InsertHandlerImpl;
import com.jddup.program.dao.handler.impl.QueryHandlerImpl;
import com.jddup.program.dao.handler.impl.UpdateHandlerImpl;
import com.jddup.program.dao.sqlbuilder.mysql.MysqlDeletePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.mysql.MysqlInsertPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.mysql.MysqlQueryPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.mysql.MysqlUpdatePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.postgresql.PostgresqlDeletePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.postgresql.PostgresqlInsertPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.postgresql.PostgresqlQueryPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.postgresql.PostgresqlUpdatePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.sqlserver.SqlServerDeletePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.sqlserver.SqlServerInsertPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.sqlserver.SqlServerQueryPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.sqlserver.SqlServerUpdatePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.voltdb.VoltdbDeletePrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.voltdb.VoltdbInsertPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.voltdb.VoltdbQueryPrepareSQLBuilder;
import com.jddup.program.dao.sqlbuilder.voltdb.VoltdbUpdatePrepareSQLBuilder;
import com.jddup.program.dao.statement.InsertPrepareStatementSetter;
import com.jddup.program.dao.statement.UpdatePrepareStatementSetter;
import com.jddup.program.dao.statement.voltdb.VoltdbInsertPrepareStatementSetter;
import com.jddup.program.dao.statement.voltdb.VoltdbUpdatePrepareStatementSetter;
import com.jddup.program.etm.EntityToTableMetaConvertor;
import com.jddup.program.etm.EntityToTableMetaConvertorImpl;
import com.jddup.program.etm.mysql.MysqlFieldToTableColumnConvertor;
import com.jddup.program.etm.mysql.MysqlTableColumnColumnDesConvertor;
import com.jddup.program.etm.postgresql.PostgresqlFieldToTableColumnConvertor;
import com.jddup.program.etm.postgresql.PostgresqlTableColumnColumnDesConvertor;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * Created by ZZB on 2017/12/3.
 */
public class DaoTemplate {
    private IInsertHandler IInsertHandler;
    private IQueryHandler IQueryHandler;
    private IUpdateHandler IUpdateHandler;
    private IDeleteHandler IDeleteHandler;
    private DataSource dataSource;

    public DaoTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
        String databaseProductName = null;
        try (Connection connection = dataSource.getConnection()) {
            databaseProductName = connection.getMetaData().getDatabaseProductName();
        } catch (SQLException e) {
            throw new JddupException("初始化DaoTemplate失败", e);
        }
        EntityToTableMetaConvertor entityToTableMetaConvertor = null;
        if (databaseProductName.equalsIgnoreCase("mysql")) {
            entityToTableMetaConvertor = new EntityToTableMetaConvertorImpl(new MysqlFieldToTableColumnConvertor(),
                    new MysqlTableColumnColumnDesConvertor());
            IInsertHandler = new InsertHandlerImpl(new MysqlInsertPrepareSQLBuilder(), new InsertPrepareStatementSetter(), entityToTableMetaConvertor);
            IQueryHandler = new QueryHandlerImpl(new MysqlQueryPrepareSQLBuilder(), entityToTableMetaConvertor);
            IUpdateHandler = new UpdateHandlerImpl(new MysqlUpdatePrepareSQLBuilder(), new UpdatePrepareStatementSetter(), entityToTableMetaConvertor);
            IDeleteHandler = new DeleteHandlerImpl(new MysqlDeletePrepareSQLBuilder(), entityToTableMetaConvertor);

        } else if (databaseProductName.equalsIgnoreCase("postgresql")) {
            entityToTableMetaConvertor = new EntityToTableMetaConvertorImpl(new PostgresqlFieldToTableColumnConvertor(),
                    new PostgresqlTableColumnColumnDesConvertor());
            IInsertHandler = new InsertHandlerImpl(new PostgresqlInsertPrepareSQLBuilder(), new InsertPrepareStatementSetter(), entityToTableMetaConvertor);
            IQueryHandler = new QueryHandlerImpl(new PostgresqlQueryPrepareSQLBuilder(), entityToTableMetaConvertor);
            IUpdateHandler = new UpdateHandlerImpl(new PostgresqlUpdatePrepareSQLBuilder(), new UpdatePrepareStatementSetter(), entityToTableMetaConvertor);
            IDeleteHandler = new DeleteHandlerImpl(new PostgresqlDeletePrepareSQLBuilder(), entityToTableMetaConvertor);
        } else if (databaseProductName.equalsIgnoreCase("voltdb")) {
            entityToTableMetaConvertor = new EntityToTableMetaConvertorImpl(new MysqlFieldToTableColumnConvertor(),
                    new MysqlTableColumnColumnDesConvertor());
            IInsertHandler = new InsertHandlerImpl(new VoltdbInsertPrepareSQLBuilder(), new VoltdbInsertPrepareStatementSetter(), entityToTableMetaConvertor);
            IQueryHandler = new QueryHandlerImpl(new VoltdbQueryPrepareSQLBuilder(), entityToTableMetaConvertor);
            IUpdateHandler = new UpdateHandlerImpl(new VoltdbUpdatePrepareSQLBuilder(), new VoltdbUpdatePrepareStatementSetter(), entityToTableMetaConvertor);
            IDeleteHandler = new DeleteHandlerImpl(new VoltdbDeletePrepareSQLBuilder(), entityToTableMetaConvertor);
        }else if (databaseProductName.equalsIgnoreCase("Microsoft SQL Server")) {
            entityToTableMetaConvertor = new EntityToTableMetaConvertorImpl(new MysqlFieldToTableColumnConvertor(),
                    new MysqlTableColumnColumnDesConvertor());
            IInsertHandler = new InsertHandlerImpl(new SqlServerInsertPrepareSQLBuilder(), new InsertPrepareStatementSetter(), entityToTableMetaConvertor);
            IQueryHandler = new QueryHandlerImpl(new SqlServerQueryPrepareSQLBuilder(), entityToTableMetaConvertor);
            IUpdateHandler = new UpdateHandlerImpl(new SqlServerUpdatePrepareSQLBuilder(), new UpdatePrepareStatementSetter(), entityToTableMetaConvertor);
            IDeleteHandler = new DeleteHandlerImpl(new SqlServerDeletePrepareSQLBuilder(), entityToTableMetaConvertor);
        }
    }

    public int updateBySQL(String sql) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateBySQL(sql, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public int updateBySQL(String sql, Object[] objects) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateBySQL(sql, objects, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int update(Object o) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.update(o, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int update(Object o, String tableName) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.update(o, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int[] updateList(List<?> objects) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateList(objects, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int[] updateList(List<?> objects, String tableName) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateList(objects, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int updateField(Object pk, Class<?> tClass, String updateField, Object value) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateField(pk, tClass, updateField, value, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int updateField(Object pk, String tableName, Class<?> tClass, String updateField, Object value) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateField(pk, tableName, tClass, updateField, value, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int updateListField(List<?> pk, Class<?> tClass, String updateField, Object value) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateListField(pk, tClass, updateField, value, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int updateListField(List<?> pk, String tableName, Class<?> tClass, String updateField, Object value) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IUpdateHandler.updateListField(pk, tableName, tClass, updateField, value, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int insert(Object o) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IInsertHandler.insert(o, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int insert(Object o, String tableName) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IInsertHandler.insert(o, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int[] insertList(List<?> objects) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IInsertHandler.insertList(objects, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int[] insertList(List<?> objects, String tableName) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IInsertHandler.insertList(objects, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public void executeSQL(String sql) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        }
        if (connection != null) {
            try (Statement statement = connection.createStatement()) {
                statement.execute(sql);
            } catch (SQLException sqlException) {
                throw new JddupException("获取数据库连接失败", sqlException);
            }
        }
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public <T> int deleteByPk(Object pk, Class<T> tClass) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IDeleteHandler.deleteByPk(pk, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> int[] deleteInPk(List<Object> pk, Class<T> tClass) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IDeleteHandler.deleteInPk(pk, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public int delete(Object o) throws JddupException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IDeleteHandler.delete(o, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> T getBy(Object pk, Class<T> tClass) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.getBy(pk, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> T findBy(String c, Object o, Class<T> tClass) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.findBy(c, o, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> List<T> queryBy(String c, Object o, Class<T> tClass) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.queryBy(c, o, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> long countBy(String c, Object o, Class<T> tClass) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.countBy(c, o, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> List<T> query(String sql, Class<T> tClass) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.query(sql, tClass, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> List<T> query(String sql, Class<T> tClass, Object[] objects) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.query(sql, tClass, objects, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public long queryCount(String sql) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.queryCount(sql, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public long queryCount(String sql, Object[] objects) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.queryCount(sql, objects, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> T getBy(Object pk, Class<T> tClass, String tableName) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.getBy(pk, tClass, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> T findBy(String c, Object o, Class<T> tClass, String tableName) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.findBy(c, o, tClass, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> List<T> queryBy(String c, Object o, Class<T> tClass, String tableName) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.queryBy(c, o, tClass, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    public <T> long countBy(String c, Object o, Class<T> tClass, String tableName) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return IQueryHandler.countBy(c, o, tClass, tableName, connection);
        } catch (SQLException e) {
            throw new JddupException("获取数据库连接失败", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}
